/*************************************************************************
 *                    free                     *
 *************************************************************************
 *************************************************************************
 * Filename	   : table_pat.c
 * Description   : This file contains the functions do with the PAT
 * Version	   : 1.0
 * History       :
 free 2013-4-15  Create
 *************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "section.h"
#include "table_pat.h"

#define PAT_TABLE_ID	0x00
#define PAT_PACKAGE_ID	0x00

/*************************************************************************
 * Function Name : ParseProgram
 * Description   : get the structure PROGRAM from array bytes
 * Parameters    :
 * Returns       :
 **************************************************************************/
static void ParseProgram(PROGRAM *pstProgram, unsigned char *pucBuffer)
{
	pstProgram->program_number = (pucBuffer[0] << 8) | pucBuffer[1];
	pstProgram->reserved = (pucBuffer[2] >> 5) & 0x07;
	pstProgram->PID = ((pucBuffer[2] & 0x1F) << 8) | pucBuffer[3];
	pstProgram->pstNext = NULL;
}

/*************************************************************************
 * Function Name : GetProgramList
 * Description   : get all the programs in a byte array and link them to a list
 * Parameters    :
 * Returns       :
 **************************************************************************/
static PROGRAM *GetProgramList(unsigned char *pucBuffer, int iProgramSize)
{
	int iReadCounter = 0;
	PROGRAM *pstPrograms = NULL;
	PROGRAM *pstTemp = NULL;
	PROGRAM *pstNew = NULL;
	while (iReadCounter < iProgramSize)
	{
		pstNew = (PROGRAM *)malloc(sizeof(PROGRAM));
		ParseProgram(pstNew, pucBuffer);
		if (pstPrograms == NULL )
		{
			pstPrograms = pstNew;
		}
		else
		{
			pstTemp->pstNext = pstNew;
		}
		pstTemp = pstNew;
		iReadCounter += 4;
		pucBuffer += 4;
	}
	return pstPrograms;
}

/*************************************************************************
 * Function Name : FreeProgramList
 * Description   : free all the programs in the program list
 * Parameters    :
 * Returns       :
 **************************************************************************/
static void FreeProgramList(PROGRAM **ppstPrograms)
{
	PROGRAM *pstTemp = NULL;
	while ((*ppstPrograms) != NULL )
	{
		pstTemp = *ppstPrograms;
		*ppstPrograms = (*ppstPrograms)->pstNext;
		free(pstTemp);
	}
}

/*************************************************************************
 * Function Name : GetSectionPat
 * Description   : get one PAT section from a byte array
 * Parameters    :
 * Returns       :
 **************************************************************************/
static SECTION_PAT *GetSectionPat(unsigned char *pucBuffer)
{
	SECTION_PAT *pstSectionPat = (SECTION_PAT *)malloc(sizeof(SECTION_PAT));
	pstSectionPat->table_id = pucBuffer[0];
	pstSectionPat->section_syntax_indicator = (pucBuffer[1] >> 7) & 0x01;
	pstSectionPat->reserved_future_use = (pucBuffer[1] >> 6) & 0x1;
	pstSectionPat->reserved1 = (pucBuffer[1] >> 4) & 0x3;
	pstSectionPat->section_length = ((pucBuffer[1] & 0x0F) << 8) | pucBuffer[2];
	pstSectionPat->transport_stream_id = (pucBuffer[3] << 8) | pucBuffer[4];
	pstSectionPat->reserved2 = (pucBuffer[5] >> 6) & 0x03;
	pstSectionPat->version_number = (pucBuffer[5] >> 1) & 0x1F;
	pstSectionPat->current_next_indicator = pucBuffer[5] & 0x01;
	pstSectionPat->section_number = pucBuffer[6];
	pstSectionPat->last_section_number = pucBuffer[7];
	pstSectionPat->pstPrograms = GetProgramList(pucBuffer + 8, pstSectionPat->section_length - 5 - 4);
	pstSectionPat->pstNext = NULL;
	return pstSectionPat;
}

/*************************************************************************
 * Function Name : GetTablePat
 * Description   : get all PAT sections from a TS file and link them to a list
 * Parameters    :
 * Returns       :	NULL --  no pat in the file
 **************************************************************************/
SECTION_PAT *GetTablePat(FILE *pInputFile, long int liFirstPackageOffset, int iPackageLength)
{
	SECTION_PAT *pstTablePat = NULL;
	SECTION_PAT *pstTemp = NULL;
	SECTION_PAT *pstNew = NULL;
	SECTION *pstSection = NULL;
	SECTION *pstSectionTemp = NULL;

	pstSection = GetSectionList(pInputFile, liFirstPackageOffset, iPackageLength, PAT_PACKAGE_ID, PAT_TABLE_ID);
	pstSectionTemp = pstSection;
	while (pstSectionTemp != NULL )
	{
		pstNew = GetSectionPat(pstSectionTemp->pucData);
		if (pstTablePat == NULL )
		{
			pstTablePat = pstNew;
		}
		else
		{
			pstTemp->pstNext = pstNew;
		}
		pstTemp = pstNew;
		pstSectionTemp = pstSectionTemp->pstNext;
	}
	FreeSectionList(&pstSection);
	return pstTablePat;
}

/*************************************************************************
 * Function Name : FreeTablePat
 * Description   : free all the PATs in a PAT list and free their programs
 * Parameters    :
 * Returns       :
 **************************************************************************/
void FreeTablePat(SECTION_PAT **ppstTablePat)
{
	SECTION_PAT *pstTemp = NULL;
	while ((*ppstTablePat) != NULL )
	{
		pstTemp = *ppstTablePat;
		*ppstTablePat = (*ppstTablePat)->pstNext;
		FreeProgramList(&(pstTemp->pstPrograms));
		free(pstTemp);
	}
}

